<script setup lang="ts">
import type { FormRules } from 'element-plus';

import type { PropType } from 'vue';

import { onMounted, reactive, ref, toRefs } from 'vue';

import { ElQuestionFilled } from '@vben/icons';

import { StorageManager } from '@vben-core/shared/cache';

import {
  ElButton,
  ElDialog,
  ElDivider,
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElMessage,
  ElOption,
  ElRadio,
  ElRadioGroup,
  ElScrollbar,
  ElSelect,
  ElTable,
  ElTableColumn,
} from 'element-plus';
import JSZip from 'jszip';

import { fileApi, publicResourcesApi } from '#/api';

interface FileData {
  id: string;
  label: string;
  type: string;
  catalogId: string;
}
interface CatalogListData {
  id: string;
  name: string;
  type: string;
  updatedTime: string;
  createdTime: string;
  publishCount: number;
  downloadCount: number;
  ownerCount: number;
  previewCount: number;
  size: number;
}
interface TileListData {
  id: string;
  name: string;
  type: string;
  updatedTime: string;
  size: string;
  directoryName: any;
  TileNum: number;
}
const props = defineProps({
  isPublic: {
    type: Boolean,
    default: false,
  },
  isPublishDialogShow: {
    type: Boolean,
    default: false,
  },
  currentSelectedData: {
    type: Object as PropType<FileData>,
    default: () => ({
      id: '',
      label: '',
      type: '',
      catalogId: '',
    }),
  },
});

const emit = defineEmits(['closePublishDialog', 'finishPublish']);

const storageManager = new StorageManager({
  prefix: '',
  storageType: 'sessionStorage',
});

const { isPublic, isPublishDialogShow, currentSelectedData } = toRefs(props);
const tableLayout = ref('fixed');
const publishloading = ref(false);
const tileLoading = ref(true);
const isCpgDialogShow = ref(false);
const isRasterTileShow = ref(false);
const isTile = ref(false);
const userId = storageManager.getItem('userId');
const tifFileName = ref('');
const tilesZipId = ref('');
const TileNum = ref();
const publishRules = reactive<FormRules>({
  noSuffixName: [
    { required: true, message: '发布资源名称不能为空！', trigger: 'blur' },
  ],
  srid: [{ required: true, message: '空间参考不能为空！', trigger: 'blur' }],
  code: [{ required: true, message: '编码方式不能为空！', trigger: 'blur' }],
  rasterTile: [
    { required: true, message: '未选择瓦片数据集！', trigger: 'blur' },
  ],
  publishType: [
    { required: true, message: '未选择发布方式！', trigger: 'blur' },
  ],
});
const publishFormData = reactive({
  shpData: {
    name: '',
    srid: '',
    code: '',
    noSuffixName: '',
  },
  geojsonData: {
    name: '',
    noSuffixName: '',
  },
  geotiffData: {
    name: '',
    noSuffixName: '',
    rasterTile: '',
    publishType: '',
  },
  imageData: {
    name: '',
    bbox: [] as number[],
    noSuffixName: '',
  },
});
const catalogList = reactive({
  data: [] as CatalogListData[],
});

const tilesData = reactive({
  data: [] as TileListData[],
});

const handleRadioChange = (_value: any) => {
  // console.log(isTile.value);
};
const showTileRaster = () => {
  isRasterTileShow.value = true;
  tileLoading.value = true;
  tilesData.data = [];

  const filteredData = catalogList.data.filter((row) =>
    row.name.toLowerCase().endsWith('.zip'),
  );
  const promises = filteredData.map((item) => {
    return fileApi
      .getFilePreviewUrl(item.id)
      .then((previewURL) => {
        return fetch(previewURL)
          .then((response) => response.arrayBuffer())
          .then((arrayBuffer) => {
            const blob = new Blob([arrayBuffer], { type: 'application/zip' });
            return new Promise((resolve, reject) => {
              const reader = new FileReader();
              reader.onloadend = () => {
                const zip = new JSZip();
                zip
                  .loadAsync(reader.result as ArrayBuffer)
                  .then(() => {
                    const topLevelDirectories = new Set();
                    zip.forEach((relativePath) => {
                      const directoryName = relativePath.split('/')[0];
                      topLevelDirectories.add(directoryName);
                    });

                    const allDigits = [...topLevelDirectories].every((value) =>
                      /^\d+$/.test(value as string),
                    );
                    if (allDigits) {
                      tilesData.data.push({
                        id: item.id,
                        name: item.name,
                        type: item.type,
                        updatedTime: item.updatedTime,
                        size: `${(item.size / 1024 / 1024).toFixed(2)}MB`,
                        directoryName: [...topLevelDirectories],
                        TileNum: topLevelDirectories.size,
                      });
                    }
                    resolve();
                  })
                  .catch(reject);
              };
              // eslint-disable-next-line unicorn/prefer-add-event-listener
              reader.onerror = reject;
              // eslint-disable-next-line unicorn/prefer-blob-reading-methods
              reader.readAsArrayBuffer(blob);
            });
          });
      })
      .catch(console.error);
  });

  Promise.all(promises).then(() => {
    tileLoading.value = false;
  });
};

const handleExpandChange = (row: any, expanded: any) => {
  if (expanded) {
    try {
      fileApi.getFilePreviewUrl(row.id).then((previewURL) => {
        fetch(previewURL)
          .then((response) => response.arrayBuffer())
          .then((arrayBuffer) => {
            const blob = new Blob([arrayBuffer], { type: 'application/zip' });
            const reader = new FileReader();
            reader.onloadend = () => {
              const zip = new JSZip();
              const topLevelDirectories: Set<string> = new Set();
              zip.loadAsync(reader.result as ArrayBuffer).then(() => {
                zip.forEach((relativePath) => {
                  const directoryName = relativePath.split('/')[0];
                  topLevelDirectories.add(directoryName);
                });
                TileNum.value = topLevelDirectories.size;
              });
            };
            // eslint-disable-next-line unicorn/prefer-blob-reading-methods
            reader.readAsArrayBuffer(blob);
          });
      });
    } catch (error) {
      console.error(error);
    }
  }
};

const getCatalogList = async () => {
  const response = await fileApi.getChildrenofcatalog(
    currentSelectedData.value.catalogId,
  );
  catalogList.data = response;
};
// 发布矢量
const publish2VectorService = async () => {
  let data: any;
  if (currentSelectedData.value.type === 'shp') {
    data = {
      userId,
      name: publishFormData.shpData.noSuffixName,
      fileId: currentSelectedData.value.id,
      catalogId: currentSelectedData.value.catalogId,
      srid: publishFormData.shpData.srid,
      code: publishFormData.shpData.code,
    };
    if (!data.name || !data.srid || !data.code) {
      ElMessage({
        type: 'warning',
        message: '请填写完整的发布信息',
      });
      return;
    }
    publishloading.value = true;
  } else {
    data = {
      userId,
      name: publishFormData.geojsonData.noSuffixName,
      fileId: currentSelectedData.value.id,
    };
    if (!data.name) {
      ElMessage({
        type: 'warning',
        message: '请填写名称',
      });
      return;
    }
  }
  // console.log('data', data);

  try {
    if (isPublic.value) {
      currentSelectedData.value.type === 'shp'
        ? await fileApi.publishShp2VectorService(data)
        : await publicResourcesApi.publishGeoJSON2VectorS(data);
    } else {
      currentSelectedData.value.type === 'shp'
        ? await fileApi.publishShp2VectorService(data)
        : await fileApi.publishGeojson2VectorService(data);
    }

    emit('finishPublish');
    ElMessage({
      type: 'success',
      message: '发布成功！',
    });
    emit('closePublishDialog');
    publishloading.value = false;
  } catch (error) {
    console.error('error submit!', error);
    ElMessage({
      type: 'error',
      message: '发布失败',
    });
    publishloading.value = false;
    return false;
  }
};
// 发布栅格（图片）
const publish2RasterService = async () => {
  let data: any;
  //  tif的发布：tif2image/tif2tile
  if (['tif', 'tiff'].includes(currentSelectedData.value.type)) {
    // tif到瓦片
    data = isTile.value
      ? {
          userId,
          serviceName: publishFormData.geotiffData.noSuffixName,
          tifFileId: currentSelectedData.value.id,
          tilesZipId: tilesZipId.value,
        }
      : {
          userId,
          fileId: currentSelectedData.value.id,
          name: `${publishFormData.geotiffData.noSuffixName}_${Date.now()}`,
        };
  }
  // 图片发布到image：图片到图片
  else {
    data = {
      userId,
      fileId: currentSelectedData.value.id,
      name: publishFormData.imageData.noSuffixName,
      bbox: publishFormData.imageData.bbox,
    };
  }

  if (!data.name && !data.serviceName) {
    ElMessage({
      type: 'warning',
      message: '请填写发布的栅格资源名称',
    });
    return;
  }
  publishloading.value = true;

  if (isPublic.value) {
    if (['tif', 'tiff'].includes(currentSelectedData.value.type)) {
      isTile.value
        ? await fileApi.publishTiff2TMS(data)
        : await publicResourcesApi.publishTiff2ImgRasterS(data);
    } else {
      // 暂不支持在公共资源下image的发布
      // response = await fileApi.publishImage2RasterService(data);
    }
  } else {
    if (['tif', 'tiff'].includes(currentSelectedData.value.type)) {
      isTile.value
        ? await fileApi.publishTiff2TMS(data)
        : await fileApi.publishTiff2ImgRasterS(data);
    } else {
      await fileApi.publishImage2RasterService(data);
    }
  }

  emit('finishPublish');
  ElMessage({
    type: 'success',
    message: '发布成功！',
  });

  emit('closePublishDialog');
  publishloading.value = false;
};

const confirmFileId = (scope: any) => {
  const fileId = scope.row.id;
  publishFormData.shpData.code = fileId;
  isCpgDialogShow.value = false;
};

const confirmTileId = (scope: any) => {
  tilesZipId.value = scope.row.id;
  tifFileName.value = scope.row.name;
  isRasterTileShow.value = false;
};
const handleCloseThisDialog = () => {
  isCpgDialogShow.value = false;
};
const handleCloseRasterTile = () => {
  isRasterTileShow.value = false;
};
onMounted(() => {
  // console.log(currentSelectedData);
  getCatalogList();
  if (currentSelectedData.value.id) {
    publishFormData.shpData.noSuffixName = currentSelectedData.value.label
      .split('.')
      .slice(0, -1)
      .join('.');
    publishFormData.geojsonData.noSuffixName = currentSelectedData.value.label
      .split('.')
      .slice(0, -1)
      .join('.');
    publishFormData.imageData.noSuffixName = currentSelectedData.value.label
      .split('.')
      .slice(0, -1)
      .join('.');
    publishFormData.geotiffData.noSuffixName = currentSelectedData.value.label
      .split('.')
      .slice(0, -1)
      .join('.');
  } else {
    ElMessage.error('未选择数据');
  }
});
</script>

<template>
  <!-- 发布对话框 publishDialog -->
  <div v-if="isPublishDialogShow">
    <ElDialog
      style="width: 25%"
      destroy-on-close
      align-center
      draggable
      class="dialog-title"
      v-model="isPublishDialogShow"
      v-if="isPublishDialogShow"
      @close="emit('closePublishDialog')"
    >
      <template #header>
        <div class="my-header">
          <h4 style="color: rgb(48 45 45)">
            <template
              v-if="['shp', 'geojson'].includes(currentSelectedData.type)"
            >
              发布至矢量服务资源
            </template>
            <template v-else> 发布至栅格服务资源 </template>
          </h4>
        </div>
      </template>

      <ElForm
        v-if="currentSelectedData.type === 'shp'"
        v-loading="publishloading"
        class="form-container"
        :rules="publishRules"
        :model="publishFormData.shpData"
        label-width="120px"
        label-position="right"
      >
        <ElFormItem label="资源名称" size="default" prop="noSuffixName">
          <ElInput
            v-model.trim="publishFormData.shpData.noSuffixName"
            placeholder="请输入发布资源名称"
            clearable
          />
        </ElFormItem>
        <ElFormItem label="空间参考" size="default" prop="srid">
          <ElSelect
            v-model="publishFormData.shpData.srid"
            placeholder="请选择空间参考"
          >
            <ElOption label="4326" value="4326" />
          </ElSelect>
        </ElFormItem>
        <!-- 用户可选cpg -->
        <ElFormItem label="字符集编码" size="default" prop="code">
          <ElSelect
            v-model="publishFormData.shpData.code"
            placeholder="请选择字符编码"
          >
            <ElOption label="UTF-8" value="UTF-8" />
            <ElOption label="LATIN1" value="LATIN1" />
            <ElOption label="ASCII" value="ASCII" />
            <ElOption label="GB2312" value="GB2312" />
            <ElOption label="ANSI" value="ANSI" />
            <ElOption
              label="选择cpg文件"
              @click="isCpgDialogShow = true"
              value=""
            />
          </ElSelect>
        </ElFormItem>
        <ElFormItem>
          <ElDivider
            border-style="hidden"
            style="margin-top: 5px; margin-bottom: 5px"
          />
        </ElFormItem>
      </ElForm>
      <ElForm
        v-else-if="currentSelectedData.type === 'geojson'"
        v-loading="publishloading"
        class="form-container"
        :rules="publishRules"
        :model="publishFormData.geojsonData"
        label-width="120px"
        label-position="right"
      >
        <ElFormItem label="资源名称" size="default" prop="noSuffixName">
          <ElInput
            v-model.trim="publishFormData.geojsonData.noSuffixName"
            placeholder="请输入发布资源名称"
            clearable
          />
        </ElFormItem>
      </ElForm>
      <ElForm
        v-else-if="
          ['tif', 'tiff'].includes(currentSelectedData.type.toLowerCase())
        "
        v-loading="publishloading"
        class="form-container"
        :rules="publishRules"
        :model="publishFormData.geotiffData"
        label-width="120px"
        label-position="right"
      >
        <ElFormItem label="发布形式" size="default" prop="publishType">
          <div>
            <ElRadioGroup
              v-model="isTile"
              @change="handleRadioChange"
              size="large"
            >
              <ElRadio :label="false">以图片发布</ElRadio>
              <ElRadio :label="true">以瓦片发布</ElRadio>
            </ElRadioGroup>
          </div>
        </ElFormItem>
        <ElFormItem label="资源名称" size="default" prop="noSuffixName">
          <ElInput
            v-model.trim="publishFormData.geotiffData.noSuffixName"
            placeholder="请输入发布资源名称"
            clearable
          />
        </ElFormItem>
        <ElFormItem
          v-if="isTile"
          label="瓦片集数据"
          size="default"
          prop="rasterTile"
        >
          <ElButton
            @click="showTileRaster"
            plain
            type="primary"
            style="width: 100%"
          >
            请选择相应的瓦片集数据
          </ElButton>
          <template v-if="tifFileName">{{ tifFileName }}</template>
        </ElFormItem>
      </ElForm>
      <ElForm
        v-else-if="
          currentSelectedData?.type &&
          ['png', 'jpg', 'gif'].includes(currentSelectedData.type)
        "
        v-loading="publishloading"
        class="form-container"
        :rules="publishRules"
        :model="publishFormData.imageData"
        label-width="120px"
        label-position="right"
      >
        <ElFormItem label="资源名称" size="default" prop="noSuffixName">
          <ElInput
            v-model.trim="publishFormData.imageData.noSuffixName"
            placeholder="请输入发布资源名称"
            clearable
          />
        </ElFormItem>
        <!-- 添加的四个角点的输入框 -->
        <ElFormItem size="default" prop="bbox">
          <ElInput
            v-model.trim="publishFormData.imageData.bbox[0]"
            placeholder="角点1（左下）的经度"
            clearable
          />
          <ElInput
            v-model.trim="publishFormData.imageData.bbox[1]"
            placeholder="角点1（左下）的纬度"
            clearable
          />
          <ElInput
            v-model.trim="publishFormData.imageData.bbox[2]"
            placeholder="角点2（右上）的经度"
            clearable
          />
          <ElInput
            v-model.trim="publishFormData.imageData.bbox[3]"
            placeholder="角点2（右上）的纬度"
            clearable
          />
          <template #label>
            <div style="display: flex; align-items: center">
              <span>角点经纬度</span>
              <el-tooltip
                class="box-item"
                effect="dark"
                content="指定经纬度范围以在地图上呈现"
                placement="top"
              >
                <ElIcon>
                  <ElQuestionFilled />
                </ElIcon>
              </el-tooltip>
            </div>
          </template>
        </ElFormItem>
      </ElForm>
      <template #footer>
        <span class="dialog-footer">
          <ElButton
            class="mybtn"
            v-if="['shp', 'geojson'].includes(currentSelectedData.type)"
            type="primary"
            @click="publish2VectorService"
          >
            发布
          </ElButton>
          <ElButton
            v-else
            class="mybtn"
            type="primary"
            @click="publish2RasterService"
            >发布
          </ElButton>
          <ElButton class="mybtn" @click="emit('closePublishDialog')">
            取消
          </ElButton>
        </span>
      </template>
    </ElDialog>
  </div>
  <!-- 选择cpg文件 -->
  <div>
    <ElDialog
      style="width: 350px"
      destroy-on-close
      align-center
      draggable
      class="dialog-title"
      v-model="isCpgDialogShow"
      @close="handleCloseThisDialog"
    >
      <template #header>
        <div class="my-header">
          <h4 style="color: rgb(48 45 45)">选择cpg文件</h4>
        </div>
      </template>
      <ElTable
        :data="
          catalogList.data?.filter((row: CatalogListData) =>
            row.name.toLowerCase().endsWith('.cpg'),
          )
        "
        highlight-current-row
        style="width: 100%"
      >
        <ElTableColumn prop="name" label="文件名称" width="150" />
        <ElTableColumn prop="updatedTime" label="更新时间" width="130" />
        <ElTableColumn fixed="right" label="操作" width="70">
          <template #default="scope">
            <ElButton type="primary" plain @click="confirmFileId(scope)">
              选择
            </ElButton>
          </template>
        </ElTableColumn>
      </ElTable>
      <template #footer>
        <span class="dialog-footer">
          <ElButton class="mybtn" @click="handleCloseThisDialog">取消</ElButton>
        </span>
      </template>
    </ElDialog>
  </div>
  <!-- 选择瓦片集数据 -->
  <div>
    <ElDialog
      style="width: 25%"
      destroy-on-close
      align-center
      draggable
      class="dialog-title"
      v-model="isRasterTileShow"
      @close="handleCloseRasterTile"
    >
      <template #header>
        <div class="my-header">
          <h4 style="color: rgb(48 45 45)">选择瓦片集数据</h4>
        </div>
      </template>
      <ElScrollbar
        style="
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
        "
        v-loading="tileLoading"
        max-height="400px"
      >
        <ElTable
          @expand-change="handleExpandChange"
          :table-layout="tableLayout"
          stripe
          :data="tilesData.data"
          highlight-current-row
          style="width: 100%"
        >
          <ElTableColumn type="expand" width="30">
            <template #default="">
              <h3>瓦片集信息</h3>
              <ElTable :border="false" :data="tilesData.data">
                <ElTableColumn width="80" label="瓦片集级数" prop="TileNum" />
                <ElTableColumn
                  width="160"
                  label="一级目录"
                  prop="directoryName"
                />
                <ElTableColumn
                  width="80"
                  label="大小"
                  prop="size"
                /><ElTableColumn
                  width="160"
                  label="更新时间"
                  prop="updatedTime"
                />
              </ElTable>
            </template>
          </ElTableColumn>
          <ElTableColumn prop="name" label="文件名称" width="150" />
          <ElTableColumn prop="updatedTime" label="更新时间" width="180" />
          <ElTableColumn fixed="right" label="操作" width="120">
            <template #default="scope">
              <ElButton type="primary" plain @click="confirmTileId(scope)">
                选择
              </ElButton>
            </template>
          </ElTableColumn>
        </ElTable>
      </ElScrollbar>
      <template #footer>
        <span class="dialog-footer">
          <ElButton class="mybtn" @click="handleCloseRasterTile">取消</ElButton>
        </span>
      </template>
    </ElDialog>
  </div>
</template>

<style scoped>
.my-header {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  height: 40px;
  padding-top: 10px;
  padding-bottom: 5px;
  padding-left: 20px;
  font-size: 18px;
}

.dialog-footer button:first-child {
  margin-right: 10px;
}

:deep(.el-dialog) {
  height: auto;
  border-radius: 20px;
  box-shadow: 0 0 50px rgb(0 0 0 / 50%);
}

.form-container {
  padding: 20px 60px 5px 30px;
}

.mybtn {
  width: 80px;
  height: 30px;
  font-weight: bolder;
  letter-spacing: 1px;
  border-radius: 3px;
}

:deep(.el-form-item) {
  display: flex;
  align-items: center;
  justify-content: center;
}
</style>
